#!/bin/bash

staging_branch="master"
project_name="pegasus"
command_decorator="verify"

function git_current_branch()
{
    echo `git branch | fgrep "*" | cut -d " " -f 2`
}

function get_next_version()
{
    versions=(`grep "PEGASUS_VERSION" src/include/pegasus/version.h | cut -d"\"" -f 2 | sed 's/\./ /g'`)
    case $1 in
        major)
            versions[0]=$[ ${versions[0]} + 1 ]
            ;;
        minor)
            versions[1]=$[ ${versions[1]} + 1 ]
            ;;
        patch)
            if [ ${versions[2]} == "SNAPSHOT" ]; then
                versions[2]="0"
            else
                versions[2]=$[ ${versions[2]} + 1 ]
            fi
            ;;
        *)
            echo "Invalid next version type"
            exit -1
            ;;
    esac

    echo ${versions[*]} | sed 's/ /\./g'
}

function get_current_version()
{
    versions=(`grep "PEGASUS_VERSION" src/include/pegasus/version.h | cut -d"\"" -f 2 | sed 's/\./ /g'`)
    case $1 in
        major)
            echo ${versions[0]}
            ;;
        minor)
            echo ${versions[0]}.${versions[1]}
            ;;
        patch)
            echo ${versions[*]} | sed 's/ /\./g'
            ;;
        *)
            echo "Invalid current version type"
            exit -1
            ;;
    esac
}

function get_branch_type()
{
    if [ $1 = $staging_branch ]; then
        echo "staging"
    else
        echo "release"
    fi
}

function verify_command()
{
    answer=""
    echo -n -e "\033[31mExecuting command: $@, y/N?\033[0m"
    read answer
    if [ -z $answer ] || [ $answer = "y" ]; then
        eval "$@"
    else
        return -1
    fi
    return $?
}

function verbose_command()
{
    echo -e "\033[31mExec Command: $@ \033[0m"
    eval "$@"
    return $?
}

function carrot_execute()
{
    case $command_decorator in
        silence)
            eval $1
            ;;
        verbose)
            verbose_command $1
            ;;
        verify)
            verify_command $1
            ;;
        simulate)
            echo -e "\033[32m$1\033[0m"
            ;;
        *)
            echo "invalid command decorator"
            exit -1
            ;;
    esac
    if [ $? -ne 0 ]; then
        echo "error in execute command $1, simulate the remaining commands"
        command_decorator="simulate"
    fi
}

#
# patch -b|--branch branch_name -p|--commit_point commit_point -s|--start_from_this -d|--decorate decorate_type
#
function usage_patch
{
    echo "carrot patch -- apply patch to specific branch, and release a new patch version"
    echo "  -h|--help, print this help"
    echo "  -b|--branch BRANCH_NAME, the target branch. For current branch if not set"
    echo "  -p|--commit_point GIT_COMMIT_ID, cherry-pick this to the target"
    echo "  -s|--start_from_this. If set, cherry-pick from [GIT_COMMIT_ID, HEAD] to the target"
    echo "  -d|--decorate TYPE. [silence|verbose|verify|simulate], default is verify"
}

function make_patch
{
    branch_name=""
    commit_point=""
    recent_commit=""
    starting_flag="false"
    
    while [[ $# > 0 ]]; do
        key="$1"
        case $key in
            -h|--help)
                usage_patch
                exit 0
                ;;
            -b|--branch)
                branch_name=$2
                shift
                ;;
            -p|--commit_point)
                commit_point=$2
                shift;;
            -s|--start_from_this)
                starting_flag="true"
                ;;
            -d|--decorate)
                command_decorator=$2
                shift
                ;;
            *)
                usage_patch
                exit -1
                ;;
        esac
        shift
    done

    old_branch=`git_current_branch`
    old_branch_type=`get_branch_type $old_branch`

    # only in staging branch, we try to calcuate the -s flag, AND
    # only in staging branch, we try to get the recent commit point in log
    if [ $old_branch_type == "staging" ]; then
        if [ ! -z $commit_point ]; then
            if [ $starting_flag == "true" ]; then
                recent_commit=`git log | sed -n "1p" | cut -d" " -f 2`
            fi
        else
            commit_point=`git log | sed -n "1p" | cut -d" " -f 2`
        fi
    fi

    current_branch=$old_branch
    # we don't apply the patch unless we are in a release tag
    if [ ! -z $branch_name ]; then
        carrot_execute "git checkout $branch_name"
        current_branch=$branch_name
        if [ ! -z $recent_commit ]; then
            carrot_execute "git cherry-pick $commit_point^..$recent_commit"
        elif [ -n $commit_point ]; then
            carrot_execute "git cherry-pick $commit_point"
        fi
    elif [ $old_branch_type == "staging" ]; then
        echo "Please checkout to a release branch, or give a release branch name by -b"
        exit -1
    fi

    new_version=`get_next_version patch`
    carrot_execute "./run.sh bump_version $new_version"
    carrot_execute "git commit -am \"Release $project_name $new_version\""
    carrot_execute "git tag -a v$new_version -m \"Release $project_name $new_version\""
    carrot_execute "git push -u origin $current_branch"
    carrot_execute "git push --tags"

    if [ $current_branch != $old_branch ]; then
        carrot_execute "git checkout $old_branch"
    fi
}

#
# minor-release -d|--decorate decorate_type
#
function usage_release_minor
{
    echo "carrot minor-release"
    echo "  -h|--help, print this help "
    echo "  -d|--decorate TYPE. [silence|verbose|verify|simulate], default is verify"
}

function release_minor
{
    while [[ $# > 0 ]]; do
        key="$1"
        case $key in
            -h|--help)
                usage_release_minor
                exit 0
                ;;
            -d|--decorate)
                command_decorator=$2
                shift
                ;;
        esac
        shift
    done

    this_branch=`git_current_branch`
    branch_type=`get_branch_type $this_branch`

    if [ $branch_type != "staging" ]; then
        echo "when release minor, we need to be in staging branch, currently in a $branch_type branch $this_branch"
        exit -1
    fi

    this_version=`get_current_version minor`

    # create new branch and push
    carrot_execute "git checkout -b v$this_version"
    # from a.b.SNAPSHOT -> a.b.0
    new_version=`get_next_version patch`
    # commit the release version
    carrot_execute "./run.sh bump_version $new_version"
    carrot_execute "git commit -am \"Release $project_name $new_version\""
    carrot_execute "git push -u origin v$this_version"
    # then make tag
    carrot_execute "git tag -a v$new_version -m \"Release $project_name $new_version\""
    carrot_execute "git push --tags"

    # update the staging branch's version
    carrot_execute "git checkout $this_branch"
    # from a.b.SNAPSHOT -> a.b+1.SNAPSHOT
    new_version=`get_next_version minor`
    carrot_execute "./run.sh bump_version $new_version"
    carrot_execute "git commit -am \"Bump version to $new_version\""
    carrot_execute "git push -u origin $this_branch"
}

function usage_carrot
{
    echo "carrot -- Carrot is A Release veRsiOn Tool"
    echo "  help             print the help"
    echo "  patch            Make patch"
    echo "  minor-release    Release a minor version"
}

pwd="$( cd "$( dirname "$0"  )" && pwd )"
shell_dir="$( cd $pwd/.. && pwd )"
cd $shell_dir

action=$1
case $action in
    help)
        usage_carrot ;;
    patch)
        shift
        make_patch $*
        ;;
    minor-release)
        shift
        release_minor $*
        ;;
    *)
        echo "ERROR: unknown command $cmd"
        echo
        usage_carrot
        exit -1
esac
